package com.imagecollector.common.utils;

import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Author: wrf
 * @Date: 2024/6/28 9:30
 * @Description: Redis工具类
 */
@Component
public class RedisUtils {

    private final RedisTemplate<String, Object> redisTemplate;

    public RedisUtils(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 设置缓存
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, Object value) {
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        operations.set(key, value);
    }

    /**
     * 设置缓存并指定过期时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     * @param unit    时间单位
     */
    public void set(String key, Object value, long timeout, TimeUnit unit) {
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        operations.set(key, value, timeout, unit);
    }

    /**
     * 获取缓存
     *
     * @param key 键
     * @param <T> 返回值类型
     * @return 值
     */
    public <T> T get(String key) {
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        return (T) operations.get(key);
    }

    /**
     * 删除缓存
     *
     * @param key 键
     */
    public void delete(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 判断缓存是否存在
     *
     * @param key 键
     * @return true存在 false不存在
     */
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 清理缓存中以指定前缀开头的键。
     * <p>
     * 此方法通过扫描Redis中所有匹配给定前缀的键，然后删除这些键，实现对缓存的清理。
     * 使用Redis的scan命令进行迭代搜索，以避免一次性加载大量键导致内存溢出。
     */
    public boolean cleanCacheByPrefix(List<String> prefix) {
        // 初始化一个列表，用于存储需要删除的键。
        List<String> keysToDelete = new ArrayList<>();
        // 使用try-with-resources语句确保Redis的Cursor在使用后能被正确关闭。
        prefix.forEach(p -> {
            try (Cursor<String> cursor = redisTemplate.scan(ScanOptions.scanOptions()
                    .match(p + "*")
                    .build())) {
                while (cursor.hasNext()) {
                    keysToDelete.add(cursor.next());
                }
            }
        });
        // 如果待删除列表不为空，那么批量删除这些键。
        if (!keysToDelete.isEmpty()) {
            redisTemplate.delete(keysToDelete);
        }
        // 目前此方法总是返回true，表示缓存清理操作已经被触发。
        // 返回值在未来可能会根据实际需求进行调整，以提供更准确的反馈。
        return true;
    }

}
